///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __SubEntity_H__
#define __SubEntity_H__

#include "OgrePrerequisites.h"

#include "OgreString.h"
#include "OgreRenderable.h"
#include "OgreHardwareBufferManager.h"
#include "OgreResourceGroupManager.h"

namespace Ogre {


    class _OgreExport SubEntity: public Renderable, public MemAlloc_SceneObj
    {
        // Note no virtual functions for efficiency
        friend class Entity;
        friend class SceneManager;
    protected:
        
        SubEntity(Entity* parent, SubMesh* subMeshBasis);

        
        virtual ~SubEntity();

        /// Pointer to parent.
        Entity* mParentEntity;

        /// Name of Material in use by this SubEntity.
        String mMaterialName;

        /// Cached pointer to material.
        MaterialPtr mMaterial;

        // Pointer to the SubMesh defining geometry.
        SubMesh* mSubMesh;

        /// Is this SubEntity visible?
        bool mVisible;

        /// The render queue to use when rendering this renderable
        uint8 mRenderQueueID;
        /// Flags whether the RenderQueue's default should be used.
        bool mRenderQueueIDSet;
        /// The render queue priority to use when rendering this renderable
        ushort mRenderQueuePriority;
        /// Flags whether the RenderQueue's default should be used.
        bool mRenderQueuePrioritySet;

		/// The LOD number of the material to use, calculated by Entity::_notifyCurrentCamera
		unsigned short mMaterialLodIndex;

        /// blend buffer details for dedicated geometry
        VertexData* mSkelAnimVertexData;
        /// Quick lookup of buffers
        TempBlendedBufferInfo mTempSkelAnimInfo;
		/// Temp buffer details for software Vertex anim geometry
		TempBlendedBufferInfo mTempVertexAnimInfo;
		/// Vertex data details for software Vertex anim of shared geometry
		VertexData* mSoftwareVertexAnimVertexData;
		/// Vertex data details for hardware Vertex anim of shared geometry
		/// - separate since we need to s/w anim for shadows whilst still altering
		///   the vertex data for hardware morphing (pos2 binding)
		VertexData* mHardwareVertexAnimVertexData;
		/// Have we applied any vertex animation to geometry?
		bool mVertexAnimationAppliedThisFrame;
		/// Number of hardware blended poses supported by material
		ushort mHardwarePoseCount;
		/// Cached distance to last camera for getSquaredViewDepth
		mutable Real mCachedCameraDist;
		/// The camera for which the cached distance is valid
		mutable const Camera *mCachedCamera;

        
        void prepareTempBlendBuffers(void);

    public:
        
        const String& getMaterialName() const;

        
        void setMaterialName( const String& name, const String& groupName = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME );

		
		void setMaterial( const MaterialPtr& material );

        
        virtual void setVisible(bool visible);

        
        virtual bool isVisible(void) const;

        
        virtual void setRenderQueueGroup(uint8 queueID);

        
        virtual void setRenderQueueGroupAndPriority(uint8 queueID, ushort priority);

        
        virtual uint8 getRenderQueueGroup(void) const;

        
        virtual ushort getRenderQueuePriority(void) const;

        
        virtual bool isRenderQueueGroupSet(void) const;

        
        virtual bool isRenderQueuePrioritySet(void) const;

        
        SubMesh* getSubMesh(void);

		
		Entity* getParent(void) const { return mParentEntity; }

        
        const MaterialPtr& getMaterial(void) const;

        
        Technique* getTechnique(void) const;

        
        void getRenderOperation(RenderOperation& op);

        
        void getWorldTransforms(Matrix4* xform) const;
        
        unsigned short getNumWorldTransforms(void) const;
        
        Real getSquaredViewDepth(const Camera* cam) const;
        
        const LightList& getLights(void) const;
        
        bool getCastsShadows(void) const;
		
		VertexData* _getSkelAnimVertexData(void);
		
		VertexData* _getSoftwareVertexAnimVertexData(void);
		
		VertexData* _getHardwareVertexAnimVertexData(void);
		
		TempBlendedBufferInfo* _getSkelAnimTempBufferInfo(void);
		
		TempBlendedBufferInfo* _getVertexAnimTempBufferInfo(void);
		/// Retrieve the VertexData which should be used for GPU binding
		VertexData* getVertexDataForBinding(void);

		
		void _markBuffersUnusedForAnimation(void);
		
		void _markBuffersUsedForAnimation(void);
		
		bool _getBuffersMarkedForAnimation(void) const { return mVertexAnimationAppliedThisFrame; }
		
		void _restoreBuffersForUnusedAnimation(bool hardwareAnimation);

		
		void _updateCustomGpuParameter(
			const GpuProgramParameters::AutoConstantEntry& constantEntry,
			GpuProgramParameters* params) const;

		
		void _invalidateCameraCache ()
		{ mCachedCamera = 0; }
    };
	
	

}


#endif
